﻿using Microsoft.AspNetCore.Http;

namespace ApplicationBase.Core.Helpers
{
    public interface IFileHelper
    {
        void Save(byte[] content, string path, bool overwriteIfExist = false);
        Task SaveAsync(byte[] content, string path, bool overwriteIfExist = false);
        Task SaveAsync(byte[] content, string path, CancellationToken cancellationToken, bool overwriteIfExist = false);
        void Save(IFormFile file, string path, bool overwriteIfExist = false);
        Task SaveAsync(IFormFile file, string path, bool overwriteIfExist = false);
        Task SaveAsync(IFormFile file, string path, CancellationToken cancellationToken, bool overwriteIfExist = false);
        public void Delete(string path);
        FileStream GetFileStream(string path);
        byte[] GetFileContent(string path);
        Task<byte[]> GetFileContentAsync(string path);
        Task<byte[]> GetFileContentAsync(string path, CancellationToken cancellationToken);
    }

    public class DefaultFileHelper : IFileHelper
    {
        public virtual void Save(byte[] content, string path, bool overwriteIfExist = false)
        {
            CreateDirectoryIfNotExist(path);
            using var stream = new FileStream(path, overwriteIfExist ? FileMode.Create : FileMode.CreateNew);
            stream.Write(content, 0, content.Length);
        }

        public virtual async Task SaveAsync(byte[] content, string path, bool overwriteIfExist = false)
        {
            await SaveAsync(content, path, default, overwriteIfExist);
        }

        public virtual async Task SaveAsync(byte[] content, string path, CancellationToken cancellationToken, bool overwriteIfExist = false)
        {
            CreateDirectoryIfNotExist(path);
            using var stream = new FileStream(path, overwriteIfExist ? FileMode.Create : FileMode.CreateNew);
            await stream.WriteAsync(content, cancellationToken);
        }

        public virtual void Save(IFormFile file, string path, bool overwriteIfExist = false)
        {
            CreateDirectoryIfNotExist(path);
            using var stream = new FileStream(path, overwriteIfExist ? FileMode.Create : FileMode.CreateNew);
            file.CopyTo(stream);
        }

        public virtual async Task SaveAsync(IFormFile file, string path, bool overwriteIfExist = false)
        {
            await SaveAsync(file, path, default, overwriteIfExist);
        }

        public virtual async Task SaveAsync(IFormFile file, string path, CancellationToken cancellationToken, bool overwriteIfExist = false)
        {
            CreateDirectoryIfNotExist(path);
            using var stream = new FileStream(path, overwriteIfExist ? FileMode.Create : FileMode.CreateNew);
            await file.CopyToAsync(stream, cancellationToken);
        }

        public virtual void Delete(string path)
        {
            if (File.Exists(path)) File.Delete(path);
        }

        public virtual FileStream GetFileStream(string path)
        {
            return new FileStream(path, FileMode.Open);
        }

        public virtual byte[] GetFileContent(string path)
        {
            return File.ReadAllBytes(path);
        }

        public virtual Task<byte[]> GetFileContentAsync(string path)
        {
            return File.ReadAllBytesAsync(path);
        }

        public virtual Task<byte[]> GetFileContentAsync(string path, CancellationToken cancellationToken)
        {
            return File.ReadAllBytesAsync(path, cancellationToken);
        }

        /// <summary>
        /// 若指定路径对应文件夹不存在，则创建对应文件夹。
        /// </summary>
        /// <param name="path">可能需要创建文件夹的文件的路径</param>
        /// <exception cref="ArgumentNullException">当传入路径为空，或截取的文件夹路径为空时触发。</exception>
        protected void CreateDirectoryIfNotExist(string path)
        {
            string dirPath = Path.GetDirectoryName(path);
            if (string.IsNullOrEmpty(dirPath)) 
                throw new ArgumentNullException("传入文件夹路径为空");
  
            if (!Directory.Exists(dirPath))
                Directory.CreateDirectory(dirPath);
        }
    }
}
